/*
 * ConsoleView.java
 * 
 * last update: 14.01.2010 by Stefan Saru
 * 
 * author:	Felix(felix@ulise.cs.pub.ro)
 * 
 * Obs: N/A
 */

package ide;

import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.*;
import javax.swing.plaf.*;
import javax.swing.text.*;
import javax.swing.tree.*;
import javax.swing.undo.*;
import javax.swing.text.html.*;

import middle.*;
/**
 * This is the console for the interpretor.
 * It contains a list acting like an output for the interpreter
 * and an input field for commands (Alec wanted this.);
 * 
 * @ver 1.0
 * @author Lucian Felix Ghita
 */
@SuppressWarnings("serial")
public class ConsoleView extends JPanel implements IOManager { 

	JList list;
	JTextField inputField;
	JScrollPane scrollPane;
	private Project project;
	private String command = "";
	private boolean commandReady = false;
	DefaultListModel listModel;
	int consoleCellHeight;

	/**
	 * The console capacity.
	 */
	static int maxLineCount = 200;

	static int tabSize = 8;

	public ConsoleView(Project project) {
		super();    
		vide.spl.showStatus("Creating console ..");

		this.project = project;
		project.cv =this;


		listModel = new DefaultListModel();
		list = new JList(listModel);
		list.setFixedCellHeight(consoleCellHeight = (int) list.getCellRenderer().
				getListCellRendererComponent(list, "Babau", 0, false, false).getPreferredSize().getHeight());

		MouseListener mouseListener = new MouseAdapter() {
			public void mouseClicked(MouseEvent e) {
				if (e.getClickCount() == 2) itemDClicked(list.locationToIndex(e.getPoint()));
			}};
			list.addMouseListener(mouseListener);
			list.setSelectionBackground(new Color(0, 200, 0));

			JPanel bottomPanel = new JPanel(new BorderLayout());
			inputField = new JTextField();

			//inputField.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, ActionEvent.CTRL_MASK + ActionEvent.ALT_MASK, false));
			inputField.setFocusAccelerator('x');
			inputField.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					commandDispatch(e.getActionCommand()); 
				}
			});

			bottomPanel.add(inputField, BorderLayout.CENTER);
			JButton clearConsole = new JButton("C");
			clearConsole.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					//setVisible(false);
					clear(); 
				}
			});

			bottomPanel.add(clearConsole, BorderLayout.EAST);

			scrollPane = new JScrollPane(list);
			scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
			scrollPane.setBackground(list.getBackground());
			setBorder(new EtchedBorder());
			setLayout(new BorderLayout());
			add(scrollPane, BorderLayout.CENTER);
			add(bottomPanel, BorderLayout.SOUTH);
			vide.spl.showStatus("Done creating console ..");
	}

	public void commandDispatch(String s) {
		command = s;
		commandReady = true;
		//writeLine(command);
		try {
			inputField.getDocument().remove(0, inputField.getDocument().getLength());
		} catch (Exception e) { System.out.println(" " + e);}


		//listModel.clear();
	}

	public String cin() {
		project.go("Ready");
		String s =  readLine();
		project.go("Running");
		return s;
	};

	/**
	 * To be used _ONLY_ fom outside the message dispatcher (i.e. only
	 *  from simulation  threads. It will block otharwise !
	 */
	public void cout(String string) {
		int lineEnd;
		while((lineEnd = string.indexOf('\n')) != -1) {
			writeLine(string.substring(0, lineEnd));
			string = string.substring(lineEnd+1, string.length());
		}
		if (string.length() > 0)
			writeLine(string);
		try {
			SwingUtilities.invokeAndWait(new Runnable() {
				public void run () {
					repaint();
				}
			});
		} catch (Exception ex) {}
	}

	/**
	 * This method does the same as cout, except
	 * throwing an Error when called from AWT thread.
	 */
	public void message(String string) {
		int lineEnd;
		while((lineEnd = string.indexOf('\n')) != -1) {
			writeLine(string.substring(0, lineEnd));
			string = string.substring(lineEnd+1, string.length());
		}
		if (string.length() > 0)
			writeLine(string);
		repaint();
	}


	public void setConsoleCapacity(int newCapacity){
		if(newCapacity < maxLineCount){
			int toBeRemoved = listModel.size() - newCapacity;
			if(toBeRemoved > 0)
				listModel.removeRange(0, toBeRemoved);
		}
		maxLineCount = newCapacity;
	}

	/**
	 * Appends a line into the console, expanding any tabs according to tha
	 *tabSize property.
	 */
	public void writeLine(String s) {
		//scrollPane.getViewport().setViewPosition(new Point(0, 30000));
		StringBuffer sb = new StringBuffer(s);
		for (int i = 0; i < sb.length();) {
			if (sb.charAt(i) == '\t') {
				sb.deleteCharAt(i);
				while(i % tabSize != 0)
					sb.insert(i++, ' ');
			} else i++;
		}
		if(listModel.size() == maxLineCount)listModel.remove(0);
		listModel.addElement(sb.toString());
		scrollPane.getViewport().
		setViewPosition(new Point(0, consoleCellHeight * listModel.getSize()));
	}

	public String readLine() {
		while (!commandReady)  
			try { 
				Thread.sleep(500);
			} catch (Exception e) {
				System.out.println("Exception in ConsoleView.readLine() :" + e);
			}  //todo -> wait for ThreadInterruptedException.
			commandReady = false;
			String dispCommand = command;
			command = "";
			return dispCommand;
	}

	public void clear() {
		listModel.clear();
		list.setFixedCellHeight(consoleCellHeight = (int) list.getCellRenderer().
				getListCellRendererComponent(list, "Babau", 0, false, false).getPreferredSize().getHeight());
		project.wv.clear();   //de ce?  buna intrebare.
	}

	public void itemDClicked(int index) {
		String fname, string = ((String)((listModel).elementAt(index))).trim();
		int ln, i, j = string.indexOf(':');
		if (j == -1) return;
		fname = string.substring(0, j);
		while (true) {
			i = j + 1 + string.substring(j+1).indexOf(':');
			if (i == j) return;
			try {
				ln = Integer.parseInt(string.substring(j+1, i));
				break;
			} catch (NumberFormatException ex) {
				fname = string.substring(0, i);
				j = i;
			}
		}
		project.jumpToLocation(fname, ln);
	}
}
